Skip to content

fix(sqleditor): skip read-only columns when saving inserted rows#10015

Open
asheshv wants to merge 1 commit into
pgadmin-org:masterfrom
asheshv:fix/query-tool-skip-non-editable-on-insert
Open

fix(sqleditor): skip read-only columns when saving inserted rows#10015
asheshv wants to merge 1 commit into
pgadmin-org:masterfrom
asheshv:fix/query-tool-skip-non-editable-on-insert

Conversation

@asheshv
Copy link
Copy Markdown
Contributor

@asheshv asheshv commented Jun 7, 2026

Summary

Fixes #9939.

Query Tool result sets can include expression/alias columns (e.g. first_name || ' ' || last_name AS the_name) that don't exist on the underlying table. The editability detection in is_query_resultset_updatable.py already marks them is_editable=False, so the column header correctly shows the lock icon. But when a user adds a new row, the frontend populated every column key on the new row object and shipped the whole thing to /sqleditor/save. save_changed_data accepted those keys verbatim, and the rendered INSERT referenced the alias — Postgres replied with column "the_name" does not exist in relation "some_table".

Filter on both sides:

  • Backendget_columns_types now propagates is_editable into the column metadata stored on the session (is_editable=True defaulted for View Data Tool, where columns are always real table columns).
  • Backendsave_changed_data drops non-editable keys from the added-row data before rendering insert.sql. Defense-in-depth: protects against stale/buggy clients.
  • FrontendResultSet.jsx::triggerSaveData omits cells whose column has can_edit === false from the added-row payload.

Test plan

  • python regression/runtests.py --pkg tools.sqleditor.utils.tests.test_save_changed_data — 13/13 pass, including the new TestSaveAddedRowSkipsNonEditableColumn scenario that runs the issue's exact first_name || ' ' || last_name AS the_name SELECT and verifies the INSERT succeeds.
  • python regression/runtests.py --pkg tools.sqleditor.utils.tests.test_is_query_resultset_updatable — 10/10 pass (3 OID-only scenarios skipped on PG12+, as before).
  • python regression/runtests.py --pkg tools.sqleditor.utils.tests.test_save_changed_uuid_data — 3/3 pass (the other consumer of the changed helpers).
  • make check-pep8, yarn run linter clean.
  • Manual smoke in Query Tool: run the issue's queries, add a row, F5 — INSERT should succeed and only write real columns.

Summary by CodeRabbit

Release Notes

  • Bug Fixes
    • SQL Editor now correctly saves newly-added rows when query results include non-editable columns (such as expression or alias columns), preventing save failures and invalid INSERT statements.

Query Tool result sets can include expression or alias columns
(e.g. `first_name || ' ' || last_name AS the_name`) that are not
columns of the underlying table. The editability check correctly
marked them is_editable=False, but the new-row save flow still
sent every column from the row object, so the rendered INSERT
referenced the alias and Postgres rejected the row with
`column "the_name" does not exist`.

Filter on both sides:

- get_columns_types now propagates is_editable into the column
  metadata stored on the session.
- save_changed_data drops non-editable keys from the added-row
  data before rendering insert.sql.
- ResultSet.jsx omits cells whose column has can_edit=false from
  the added-row payload sent to the server.

Adds a regression scenario in test_save_changed_data exercising
the exact concatenation-alias query from the issue report.

Fixes pgadmin-org#9939
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 7, 2026

Review Change Stack

Walkthrough

The PR fixes Query Editor failures when saving new rows in result sets containing non-editable columns (aliases, expressions). The fix filters such columns on both frontend and backend: metadata propagation adds is_editable flags, the frontend filters before sending, the backend filters during INSERT construction, and a regression test validates the scenario.

Changes

Non-editable column filtering in Query Editor saves

Layer / File(s) Summary
Non-editable column metadata propagation
web/pgadmin/tools/sqleditor/utils/get_column_types.py
The get_columns_types function adds an is_editable flag to column type descriptors, extracting it from column metadata and defaulting to True.
Frontend filtering of non-editable columns
web/pgadmin/tools/sqleditor/static/js/components/sections/ResultSet.jsx
The triggerSaveData function builds a nonEditableKeys set from columns where can_edit === false and omits those keys from each newly-added row's data before sending to the save API.
Backend filtering during insert construction
web/pgadmin/tools/sqleditor/utils/save_changed_data.py
The save_changed_data function filters row data to retain only editable columns from columns_info before rendering INSERT SQL, preventing non-existent table columns from being referenced.
Regression test for non-editable alias columns
web/pgadmin/tools/sqleditor/utils/tests/test_save_changed_data.py
A new test class TestSaveAddedRowSkipsNonEditableColumn validates the insert flow with an aliased expression column (`first_name

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(sqleditor): skip read-only columns when saving inserted rows' is concise, specific, and accurately describes the main change across frontend, backend, and test modifications.
Linked Issues check ✅ Passed The pull request fully addresses issue #9939 by implementing frontend filtering, backend filtering, and metadata propagation to prevent non-editable expression/alias columns from being referenced in INSERT statements.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the objective of skipping non-editable columns during insert operations; no unrelated modifications to unrelated features or infrastructure.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@web/pgadmin/tools/sqleditor/utils/save_changed_data.py`:
- Around line 121-129: The filtering of incoming row data currently treats
unknown column keys as editable because the predicate uses columns_info.get(k,
{}).get('is_editable', True); change the default to False so unknown keys are
rejected: update the comprehension that builds data (the dict comprehension that
references columns_info and 'is_editable') to use .get('is_editable', False) so
only known editable columns are retained before INSERT rendering.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ce5ec567-c303-4937-8f91-14fa9791425d

📥 Commits

Reviewing files that changed from the base of the PR and between 291a55e and 0f8a14b.

📒 Files selected for processing (4)
  • web/pgadmin/tools/sqleditor/static/js/components/sections/ResultSet.jsx
  • web/pgadmin/tools/sqleditor/utils/get_column_types.py
  • web/pgadmin/tools/sqleditor/utils/save_changed_data.py
  • web/pgadmin/tools/sqleditor/utils/tests/test_save_changed_data.py

Comment on lines +121 to +129
# Drop any column the client included that isn't a real
# editable column of the underlying table (e.g.
# `first_name || ' ' || last_name as the_name`). Without
# this guard the rendered INSERT references a non-existent
# column and Postgres rejects the row. Issue #9939.
data = {
k: v for k, v in data.items()
if columns_info.get(k, {}).get('is_editable', True)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reject unknown client keys in added-row filtering.

The current predicate defaults unknown keys to editable (True), so non-schema keys can still pass through and reach INSERT rendering. That undermines the defense-in-depth this block is adding.

Proposed fix
-                data = {
-                    k: v for k, v in data.items()
-                    if columns_info.get(k, {}).get('is_editable', True)
-                }
+                data = {
+                    k: v for k, v in data.items()
+                    if k in columns_info and
+                    columns_info[k].get('is_editable', True)
+                }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/pgadmin/tools/sqleditor/utils/save_changed_data.py` around lines 121 -
129, The filtering of incoming row data currently treats unknown column keys as
editable because the predicate uses columns_info.get(k, {}).get('is_editable',
True); change the default to False so unknown keys are rejected: update the
comprehension that builds data (the dict comprehension that references
columns_info and 'is_editable') to use .get('is_editable', False) so only known
editable columns are retained before INSERT rendering.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Query Editor Cannot Recognize Non-Updatable Fields

1 participant